home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_kernel_source / KERNEL / SYSCTL.C < prev    next >
C/C++ Source or Header  |  1999-09-17  |  26KB  |  1,135 lines

  1. /*
  2.  * sysctl.c: General linux system control interface
  3.  *
  4.  * Begun 24 March 1995, Stephen Tweedie
  5.  * Added /proc support, Dec 1995
  6.  * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas.
  7.  * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver.
  8.  * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver.
  9.  * Dynamic registration fixes, Stephen Tweedie.
  10.  * Added kswapd-interval, ctrl-alt-del, printk stuff, 1/8/97, Chris Horn.
  11.  * Made sysctl support optional via CONFIG_SYSCTL, 1/10/97, Chris Horn.
  12.  */
  13.  
  14. #include <linux/config.h>
  15. #include <linux/malloc.h>
  16. #include <linux/sysctl.h>
  17. #include <linux/swapctl.h>
  18. #include <linux/proc_fs.h>
  19. #include <linux/ctype.h>
  20. #include <linux/utsname.h>
  21. #include <linux/swapctl.h>
  22. #include <linux/smp_lock.h>
  23. #include <linux/init.h>
  24.  
  25. #include <asm/uaccess.h>
  26.  
  27. #ifdef CONFIG_ROOT_NFS
  28. #include <linux/nfs_fs.h>
  29. #endif
  30.  
  31. #if defined(CONFIG_SYSCTL)
  32.  
  33. /* External variables not in a header file. */
  34. extern int panic_timeout;
  35. extern int console_loglevel, C_A_D;
  36. extern int bdf_prm[], bdflush_min[], bdflush_max[];
  37. extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
  38. extern int sysctl_overcommit_memory;
  39. extern int nr_queued_signals, max_queued_signals;
  40.  
  41. #ifdef CONFIG_KMOD
  42. extern char modprobe_path[];
  43. #endif
  44. #ifdef CONFIG_CHR_DEV_SG
  45. extern int sg_big_buff;
  46. #endif
  47. #ifdef CONFIG_SYSVIPC
  48. extern int shmmax;
  49. #endif
  50.  
  51. #ifdef __sparc__
  52. extern char reboot_command [];
  53. #endif
  54. #ifdef __powerpc__
  55. extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
  56. int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
  57.           void *buffer, size_t *lenp);
  58. #endif
  59.  
  60. #ifdef CONFIG_BSD_PROCESS_ACCT
  61. extern int acct_parm[];
  62. #endif
  63.  
  64. extern int pgt_cache_water[];
  65.  
  66. static int parse_table(int *, int, void *, size_t *, void *, size_t,
  67.                ctl_table *, void **);
  68. static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
  69.           void *buffer, size_t *lenp);
  70.  
  71.  
  72. static ctl_table root_table[];
  73. static struct ctl_table_header root_table_header = 
  74.     {root_table, DNODE_SINGLE(&root_table_header)};
  75.  
  76. static ctl_table kern_table[];
  77. static ctl_table vm_table[];
  78. #ifdef CONFIG_NET
  79. extern ctl_table net_table[];
  80. #endif
  81. static ctl_table proc_table[];
  82. static ctl_table fs_table[];
  83. static ctl_table debug_table[];
  84. static ctl_table dev_table[];
  85.  
  86.  
  87. /* /proc declarations: */
  88.  
  89. #ifdef CONFIG_PROC_FS
  90.  
  91. static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
  92. static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
  93. static int proc_sys_permission(struct inode *, int);
  94.  
  95. struct file_operations proc_sys_file_operations =
  96. {
  97.     NULL,        /* lseek   */
  98.     proc_readsys,    /* read       */
  99.     proc_writesys,    /* write   */
  100.     NULL,        /* readdir */
  101.     NULL,        /* poll    */
  102.     NULL,        /* ioctl   */
  103.     NULL,        /* mmap       */
  104.     NULL,        /* no special open code       */
  105.     NULL,        /* no special flush code */
  106.     NULL,        /* no special release code */
  107.     NULL        /* can't fsync */
  108. };
  109.  
  110. struct inode_operations proc_sys_inode_operations =
  111. {
  112.     &proc_sys_file_operations,
  113.     NULL,        /* create */
  114.     NULL,        /* lookup */
  115.     NULL,        /* link */
  116.     NULL,        /* unlink */
  117.     NULL,        /* symlink */
  118.     NULL,        /* mkdir */
  119.     NULL,        /* rmdir */
  120.     NULL,        /* mknod */
  121.     NULL,        /* rename */
  122.     NULL,        /* readlink */
  123.     NULL,        /* follow_link */
  124.     NULL,        /* readpage */
  125.     NULL,        /* writepage */
  126.     NULL,        /* bmap */
  127.     NULL,        /* truncate */
  128.     proc_sys_permission
  129. };
  130.  
  131. extern struct proc_dir_entry proc_sys_root;
  132.  
  133. static void register_proc_table(ctl_table *, struct proc_dir_entry *);
  134. static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
  135. #endif
  136. extern int inodes_stat[];
  137. extern int dentry_stat[];
  138.  
  139. /* The default sysctl tables: */
  140.  
  141. static ctl_table root_table[] = {
  142.     {CTL_KERN, "kernel", NULL, 0, 0555, kern_table},
  143.     {CTL_VM, "vm", NULL, 0, 0555, vm_table},
  144. #ifdef CONFIG_NET
  145.     {CTL_NET, "net", NULL, 0, 0555, net_table},
  146. #endif
  147.     {CTL_PROC, "proc", NULL, 0, 0555, proc_table},
  148.     {CTL_FS, "fs", NULL, 0, 0555, fs_table},
  149.     {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table},
  150.         {CTL_DEV, "dev", NULL, 0, 0555, dev_table},
  151.     {0}
  152. };
  153.  
  154. static ctl_table kern_table[] = {
  155.     {KERN_OSTYPE, "ostype", system_utsname.sysname, 64,
  156.      0444, NULL, &proc_doutsstring, &sysctl_string},
  157.     {KERN_OSRELEASE, "osrelease", system_utsname.release, 64,
  158.      0444, NULL, &proc_doutsstring, &sysctl_string},
  159.     {KERN_VERSION, "version", system_utsname.version, 64,
  160.      0444, NULL, &proc_doutsstring, &sysctl_string},
  161.     {KERN_NODENAME, "hostname", system_utsname.nodename, 64,
  162.      0644, NULL, &proc_doutsstring, &sysctl_string},
  163.     {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
  164.      0644, NULL, &proc_doutsstring, &sysctl_string},
  165.     {KERN_PANIC, "panic", &panic_timeout, sizeof(int),
  166.      0644, NULL, &proc_dointvec},
  167. #ifdef CONFIG_BLK_DEV_INITRD
  168.     {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
  169.      0644, NULL, &proc_dointvec},
  170. #endif
  171. #ifdef CONFIG_BINFMT_JAVA
  172.     {KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
  173.      64, 0644, NULL, &proc_dostring, &sysctl_string },
  174.     {KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
  175.      64, 0644, NULL, &proc_dostring, &sysctl_string },
  176. #endif
  177. #ifdef __sparc__
  178.     {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
  179.      256, 0644, NULL, &proc_dostring, &sysctl_string },
  180. #endif
  181. #ifdef __powerpc__
  182.     {KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
  183.      0644, NULL, &proc_dointvec},
  184.     {KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
  185.      0644, NULL, &proc_dointvec},
  186.     {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
  187.      0644, NULL, &proc_dointvec},
  188.     {KERN_PPC_L2CR, "l2cr", NULL, 0,
  189.      0644, NULL, &proc_dol2crvec},
  190. #endif
  191.     {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int),
  192.      0644, NULL, &proc_dointvec},
  193.     {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int),
  194.      0644, NULL, &proc_dointvec},
  195. #ifdef CONFIG_KMOD
  196.     {KERN_MODPROBE, "modprobe", &modprobe_path, 256,
  197.      0644, NULL, &proc_dostring, &sysctl_string },
  198. #endif
  199. #ifdef CONFIG_CHR_DEV_SG
  200.     {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int),
  201.      0444, NULL, &proc_dointvec},
  202. #endif
  203. #ifdef CONFIG_BSD_PROCESS_ACCT
  204.     {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int),
  205.     0644, NULL, &proc_dointvec},
  206. #endif
  207.     {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int),
  208.      0444, NULL, &proc_dointvec},
  209.     {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int),
  210.      0644, NULL, &proc_dointvec},
  211. #ifdef CONFIG_SYSVIPC
  212.     {KERN_SHMMAX, "shmmax", &shmmax, sizeof (int),
  213.      0644, NULL, &proc_dointvec},
  214. #endif
  215.     {0}
  216. };
  217.  
  218. static ctl_table vm_table[] = {
  219.     {VM_FREEPG, "freepages", 
  220.      &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec},
  221.     {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
  222.      &proc_dointvec_minmax, &sysctl_intvec, NULL,
  223.      &bdflush_min, &bdflush_max},
  224.     {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory,
  225.      sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec},
  226.     {VM_BUFFERMEM, "buffermem",
  227.      &buffer_mem, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
  228.     {VM_PAGECACHE, "pagecache",
  229.      &page_cache, sizeof(buffer_mem_t), 0644, NULL, &proc_dointvec},
  230.     {VM_PAGERDAEMON, "kswapd",
  231.      &pager_daemon, sizeof(pager_daemon_t), 0644, NULL, &proc_dointvec},
  232.     {VM_PGT_CACHE, "pagetable_cache", 
  233.      &pgt_cache_water, 2*sizeof(int), 0600, NULL, &proc_dointvec},
  234.     {VM_PAGE_CLUSTER, "page-cluster", 
  235.      &page_cluster, sizeof(int), 0600, NULL, &proc_dointvec},
  236.     {0}
  237. };
  238.  
  239. static ctl_table proc_table[] = {
  240.     {0}
  241. };
  242.  
  243. static ctl_table fs_table[] = {
  244.     {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
  245.      0444, NULL, &proc_dointvec},
  246.     {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
  247.      0444, NULL, &proc_dointvec},
  248.     {FS_MAXINODE, "inode-max", &max_inodes, sizeof(int),
  249.      0644, NULL, &proc_dointvec},
  250.     {FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
  251.      0444, NULL, &proc_dointvec},
  252.     {FS_MAXFILE, "file-max", &max_files, sizeof(int),
  253.      0644, NULL, &proc_dointvec},
  254.     {FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
  255.      0444, NULL, &proc_dointvec},
  256.     {FS_MAXSUPER, "super-max", &max_super_blocks, sizeof(int),
  257.      0644, NULL, &proc_dointvec},
  258.     {FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
  259.      0444, NULL, &proc_dointvec},
  260.     {FS_MAXDQUOT, "dquot-max", &max_dquots, sizeof(int),
  261.      0644, NULL, &proc_dointvec},
  262.     {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
  263.      0444, NULL, &proc_dointvec},
  264.     {0}
  265. };
  266.  
  267. static ctl_table debug_table[] = {
  268.     {0}
  269. };
  270.  
  271. static ctl_table dev_table[] = {
  272.     {0}
  273. };  
  274.  
  275.  
  276. void __init sysctl_init(void)
  277. {
  278. #ifdef CONFIG_PROC_FS
  279.     register_proc_table(root_table, &proc_sys_root);
  280. #endif
  281. }
  282.  
  283.  
  284. int do_sysctl (int *name, int nlen,
  285.            void *oldval, size_t *oldlenp,
  286.            void *newval, size_t newlen)
  287. {
  288.     int error;
  289.     struct ctl_table_header *tmp;
  290.     void *context;
  291.     
  292.     if (nlen == 0 || nlen >= CTL_MAXNAME)
  293.         return -ENOTDIR;
  294.     
  295.     if (oldval) 
  296.     {
  297.         int old_len;
  298.         if (!oldlenp)
  299.             return -EFAULT;
  300.         if(get_user(old_len, oldlenp))
  301.             return -EFAULT;
  302.     }
  303.     tmp = &root_table_header;
  304.     do {
  305.         context = NULL;
  306.         error = parse_table(name, nlen, oldval, oldlenp, 
  307.                     newval, newlen, tmp->ctl_table, &context);
  308.         if (context)
  309.             kfree(context);
  310.         if (error != -ENOTDIR)
  311.             return error;
  312.         tmp = tmp->DLIST_NEXT(ctl_entry);
  313.     } while (tmp != &root_table_header);
  314.     return -ENOTDIR;
  315. }
  316.  
  317. extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
  318. {
  319.     struct __sysctl_args tmp;
  320.     int error;
  321.  
  322.     if(copy_from_user(&tmp, args, sizeof(tmp)))
  323.         return -EFAULT;
  324.         
  325.     lock_kernel();
  326.     error = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, tmp.oldlenp,
  327.               tmp.newval, tmp.newlen);
  328.     unlock_kernel();
  329.     return error;
  330. }
  331.  
  332. /* Like in_group_p, but testing against egid, not fsgid */
  333. static int in_egroup_p(gid_t grp)
  334. {
  335.     if (grp != current->egid) {
  336.         int i = current->ngroups;
  337.         if (i) {
  338.             gid_t *groups = current->groups;
  339.             do {
  340.                 if (*groups == grp)
  341.                     goto out;
  342.                 groups++;
  343.                 i--;
  344.             } while (i);
  345.         }
  346.         return 0;
  347.     }
  348. out:
  349.     return 1;
  350. }
  351.  
  352. /* ctl_perm does NOT grant the superuser all rights automatically, because
  353.    some sysctl variables are readonly even to root. */
  354.  
  355. static int test_perm(int mode, int op)
  356. {
  357.     if (!current->euid)
  358.         mode >>= 6;
  359.     else if (in_egroup_p(0))
  360.         mode >>= 3;
  361.     if ((mode & op & 0007) == op)
  362.         return 0;
  363.     return -EACCES;
  364. }
  365.  
  366. static inline int ctl_perm(ctl_table *table, int op)
  367. {
  368.     return test_perm(table->mode, op);
  369. }
  370.  
  371. static int parse_table(int *name, int nlen,
  372.                void *oldval, size_t *oldlenp,
  373.                void *newval, size_t newlen,
  374.                ctl_table *table, void **context)
  375. {
  376.     int error;
  377. repeat:
  378.     if (!nlen)
  379.         return -ENOTDIR;
  380.  
  381.     for ( ; table->ctl_name; table++) {
  382.         int n;
  383.         if(get_user(n,name))
  384.             return -EFAULT;
  385.         if (n == table->ctl_name ||
  386.             table->ctl_name == CTL_ANY) {
  387.             if (table->child) {
  388.                 if (ctl_perm(table, 001))
  389.                     return -EPERM;
  390.                 if (table->strategy) {
  391.                     error = table->strategy(
  392.                         table, name, nlen,
  393.                         oldval, oldlenp,
  394.                         newval, newlen, context);
  395.                 if (error)
  396.                     return error;
  397.                 }
  398.                 name++;
  399.                 nlen--;
  400.                 table = table->child;
  401.                 goto repeat;
  402.             }
  403.             error = do_sysctl_strategy(table, name, nlen,
  404.                            oldval, oldlenp,
  405.                            newval, newlen, context);
  406.             return error;
  407.         }
  408.     };
  409.     return -ENOTDIR;
  410. }
  411.  
  412. /* Perform the actual read/write of a sysctl table entry. */
  413. int do_sysctl_strategy (ctl_table *table, 
  414.             int *name, int nlen,
  415.             void *oldval, size_t *oldlenp,
  416.             void *newval, size_t newlen, void **context)
  417. {
  418.     int op = 0, rc, len;
  419.  
  420.     if (oldval)
  421.         op |= 004;
  422.     if (newval) 
  423.         op |= 002;
  424.     if (ctl_perm(table, op))
  425.         return -EPERM;
  426.  
  427.     if (table->strategy) {
  428.         rc = table->strategy(table, name, nlen, oldval, oldlenp,
  429.                      newval, newlen, context);
  430.         if (rc < 0)
  431.             return rc;
  432.         if (rc > 0)
  433.             return 0;
  434.     }
  435.  
  436.     /* If there is no strategy routine, or if the strategy returns
  437.      * zero, proceed with automatic r/w */
  438.     if (table->data && table->maxlen) {
  439.         if (oldval && oldlenp) {
  440.             get_user(len, oldlenp);
  441.             if (len) {
  442.                 if (len > table->maxlen)
  443.                     len = table->maxlen;
  444.                 if(copy_to_user(oldval, table->data, len))
  445.                     return -EFAULT;
  446.                 if(put_user(len, oldlenp))
  447.                     return -EFAULT;
  448.             }
  449.         }
  450.         if (newval && newlen) {
  451.             len = newlen;
  452.             if (len > table->maxlen)
  453.                 len = table->maxlen;
  454.             if(copy_from_user(table->data, newval, len))
  455.                 return -EFAULT;
  456.         }
  457.     }
  458.     return 0;
  459. }
  460.  
  461. struct ctl_table_header *register_sysctl_table(ctl_table * table, 
  462.                            int insert_at_head)
  463. {
  464.     struct ctl_table_header *tmp;
  465.     tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
  466.     if (!tmp)
  467.         return 0;
  468.     *tmp = ((struct ctl_table_header) {table, DNODE_NULL});
  469.     if (insert_at_head)
  470.         DLIST_INSERT_AFTER(&root_table_header, tmp, ctl_entry);
  471.     else
  472.         DLIST_INSERT_BEFORE(&root_table_header, tmp, ctl_entry);
  473. #ifdef CONFIG_PROC_FS
  474.     register_proc_table(table, &proc_sys_root);
  475. #endif
  476.     return tmp;
  477. }
  478.  
  479. /*
  480.  * Unlink and free a ctl_table.
  481.  */
  482. void unregister_sysctl_table(struct ctl_table_header * header)
  483. {
  484.     DLIST_DELETE(header, ctl_entry);
  485. #ifdef CONFIG_PROC_FS
  486.     unregister_proc_table(header->ctl_table, &proc_sys_root);
  487. #endif
  488.     kfree(header);
  489. }
  490.  
  491. /*
  492.  * /proc/sys support
  493.  */
  494.  
  495. #ifdef CONFIG_PROC_FS
  496.  
  497. /* Scan the sysctl entries in table and add them all into /proc */
  498. static void register_proc_table(ctl_table * table, struct proc_dir_entry *root)
  499. {
  500.     struct proc_dir_entry *de;
  501.     int len;
  502.     mode_t mode;
  503.     
  504.     for (; table->ctl_name; table++) {
  505.         /* Can't do anything without a proc name. */
  506.         if (!table->procname)
  507.             continue;
  508.         /* Maybe we can't do anything with it... */
  509.         if (!table->proc_handler && !table->child) {
  510.             printk(KERN_WARNING "SYSCTL: Can't register %s\n",
  511.                 table->procname);
  512.             continue;
  513.         }
  514.  
  515.         len = strlen(table->procname);
  516.         mode = table->mode;
  517.  
  518.         de = NULL;
  519.         if (table->proc_handler)
  520.             mode |= S_IFREG;
  521.         else {
  522.             mode |= S_IFDIR;
  523.             for (de = root->subdir; de; de = de->next) {
  524.                 if (proc_match(len, table->procname, de))
  525.                     break;
  526.             }
  527.             /* If the subdir exists already, de is non-NULL */
  528.         }
  529.  
  530.         if (!de) {
  531.             de = create_proc_entry(table->procname, mode, root);
  532.             if (!de)
  533.                 continue;
  534.             de->data = (void *) table;
  535.             if (table->proc_handler)
  536.                 de->ops = &proc_sys_inode_operations;
  537.  
  538.         }
  539.         table->de = de;
  540.         if (de->mode & S_IFDIR)
  541.             register_proc_table(table->child, de);
  542.     }
  543. }
  544.  
  545. /*
  546.  * Unregister a /proc sysctl table and any subdirectories.
  547.  */
  548. static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
  549. {
  550.     struct proc_dir_entry *de;
  551.     for (; table->ctl_name; table++) {
  552.         if (!(de = table->de))
  553.             continue;
  554.         if (de->mode & S_IFDIR) {
  555.             if (!table->child) {
  556.                 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
  557.                 continue;
  558.             }
  559.             unregister_proc_table(table->child, de);
  560.  
  561.             /* Don't unregister directories which still have entries.. */
  562.             if (de->subdir)
  563.                 continue;
  564.         }
  565.  
  566.         /* Don't unregoster proc entries that are still being used.. */
  567.         if (de->count)
  568.             continue;
  569.  
  570.         proc_unregister(root, de->low_ino);
  571.         table->de = NULL;
  572.         kfree(de);
  573.     }
  574. }
  575.  
  576. static ssize_t do_rw_proc(int write, struct file * file, char * buf,
  577.               size_t count, loff_t *ppos)
  578. {
  579.     int op;
  580.     struct proc_dir_entry *de;
  581.     struct ctl_table *table;
  582.     size_t res;
  583.     ssize_t error;
  584.     
  585.     de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
  586.     if (!de || !de->data)
  587.         return -ENOTDIR;
  588.     table = (struct ctl_table *) de->data;
  589.     if (!table || !table->proc_handler)
  590.         return -ENOTDIR;
  591.     op = (write ? 002 : 004);
  592.     if (ctl_perm(table, op))
  593.         return -EPERM;
  594.     
  595.     res = count;
  596.  
  597.     /*
  598.      * FIXME: we need to pass on ppos to the handler.
  599.      */
  600.  
  601.     error = (*table->proc_handler) (table, write, file, buf, &res);
  602.     if (error)
  603.         return error;
  604.     return res;
  605. }
  606.  
  607. static ssize_t proc_readsys(struct file * file, char * buf,
  608.                 size_t count, loff_t *ppos)
  609. {
  610.     return do_rw_proc(0, file, buf, count, ppos);
  611. }
  612.  
  613. static ssize_t proc_writesys(struct file * file, const char * buf,
  614.                  size_t count, loff_t *ppos)
  615. {
  616.     return do_rw_proc(1, file, (char *) buf, count, ppos);
  617. }
  618.  
  619. static int proc_sys_permission(struct inode *inode, int op)
  620. {
  621.     return test_perm(inode->i_mode, op);
  622. }
  623.  
  624. int proc_dostring(ctl_table *table, int write, struct file *filp,
  625.           void *buffer, size_t *lenp)
  626. {
  627.     int len;
  628.     char *p, c;
  629.     
  630.     if (!table->data || !table->maxlen || !*lenp ||
  631.         (filp->f_pos && !write)) {
  632.         *lenp = 0;
  633.         return 0;
  634.     }
  635.     
  636.     if (write) {
  637.         len = 0;
  638.         p = buffer;
  639.         while (len < *lenp) {
  640.             if(get_user(c, p++))
  641.                 return -EFAULT;
  642.             if (c == 0 || c == '\n')
  643.                 break;
  644.             len++;
  645.         }
  646.         if (len >= table->maxlen)
  647.             len = table->maxlen-1;
  648.         if(copy_from_user(table->data, buffer, len))
  649.             return -EFAULT;
  650.         ((char *) table->data)[len] = 0;
  651.         filp->f_pos += *lenp;
  652.     } else {
  653.         len = strlen(table->data);
  654.         if (len > table->maxlen)
  655.             len = table->maxlen;
  656.         if (len > *lenp)
  657.             len = *lenp;
  658.         if (len)
  659.             if(copy_to_user(buffer, table->data, len))
  660.                 return -EFAULT;
  661.         if (len < *lenp) {
  662.             if(put_user('\n', ((char *) buffer) + len))
  663.                 return -EFAULT;
  664.             len++;
  665.         }
  666.         *lenp = len;
  667.         filp->f_pos += len;
  668.     }
  669.     return 0;
  670. }
  671.  
  672. /*
  673.  *    Special case of dostring for the UTS structure. This has locks
  674.  *    to observe. Should this be in kernel/sys.c ????
  675.  */
  676.  
  677. static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
  678.           void *buffer, size_t *lenp)
  679. {
  680.     int r;
  681.     down(&uts_sem);
  682.     r=proc_dostring(table,write,filp,buffer,lenp);
  683.     up(&uts_sem);
  684.     return r;
  685. }
  686.  
  687. static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
  688.           void *buffer, size_t *lenp, int conv)
  689. {
  690.     int *i, vleft, first=1, len, left, neg, val;
  691.     #define TMPBUFLEN 20
  692.     char buf[TMPBUFLEN], *p;
  693.     
  694.     if (!table->data || !table->maxlen || !*lenp ||
  695.         (filp->f_pos && !write)) {
  696.         *lenp = 0;
  697.         return 0;
  698.     }
  699.     
  700.     i = (int *) table->data;
  701.     vleft = table->maxlen / sizeof(int);
  702.     left = *lenp;
  703.     
  704.     for (; left && vleft--; i++, first=0) {
  705.         if (write) {
  706.             while (left) {
  707.                 char c;
  708.                 if(get_user(c,(char *) buffer))
  709.                     return -EFAULT;
  710.                 if (!isspace(c))
  711.                     break;
  712.                 left--;
  713.                 ((char *) buffer)++;
  714.             }
  715.             if (!left)
  716.                 break;
  717.             neg = 0;
  718.             len = left;
  719.             if (len > TMPBUFLEN-1)
  720.                 len = TMPBUFLEN-1;
  721.             if(copy_from_user(buf, buffer, len))
  722.                 return -EFAULT;
  723.             buf[len] = 0;
  724.             p = buf;
  725.             if (*p == '-' && left > 1) {
  726.                 neg = 1;
  727.                 left--, p++;
  728.             }
  729.             if (*p < '0' || *p > '9')
  730.                 break;
  731.             val = simple_strtoul(p, &p, 0) * conv;
  732.             len = p-buf;
  733.             if ((len < left) && *p && !isspace(*p))
  734.                 break;
  735.             if (neg)
  736.                 val = -val;
  737.             buffer += len;
  738.             left -= len;
  739.             *i = val;
  740.         } else {
  741.             p = buf;
  742.             if (!first)
  743.                 *p++ = '\t';
  744.             sprintf(p, "%d", (*i) / conv);
  745.             len = strlen(buf);
  746.             if (len > left)
  747.                 len = left;
  748.             if(copy_to_user(buffer, buf, len))
  749.                 return -EFAULT;
  750.             left -= len;
  751.             buffer += len;
  752.         }
  753.     }
  754.  
  755.     if (!write && !first && left) {
  756.         if(put_user('\n', (char *) buffer))
  757.             return -EFAULT;
  758.         left--, buffer++;
  759.     }
  760.     if (write) {
  761.         p = (char *) buffer;
  762.         while (left) {
  763.             char c;
  764.             if(get_user(c, p++))
  765.                 return -EFAULT;
  766.             if (!isspace(c))
  767.                 break;
  768.             left--;
  769.         }
  770.     }
  771.     if (write && first)
  772.         return -EINVAL;
  773.     *lenp -= left;
  774.     filp->f_pos += *lenp;
  775.     return 0;
  776. }
  777.  
  778. int proc_dointvec(ctl_table *table, int write, struct file *filp,
  779.              void *buffer, size_t *lenp)
  780. {
  781.     return do_proc_dointvec(table,write,filp,buffer,lenp,1);
  782. }
  783.  
  784. int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
  785.           void *buffer, size_t *lenp)
  786. {
  787.     int *i, *min, *max, vleft, first=1, len, left, neg, val;
  788.     #define TMPBUFLEN 20
  789.     char buf[TMPBUFLEN], *p;
  790.     
  791.     if (!table->data || !table->maxlen || !*lenp ||
  792.         (filp->f_pos && !write)) {
  793.         *lenp = 0;
  794.         return 0;
  795.     }
  796.     
  797.     i = (int *) table->data;
  798.     min = (int *) table->extra1;
  799.     max = (int *) table->extra2;
  800.     vleft = table->maxlen / sizeof(int);
  801.     left = *lenp;
  802.     
  803.     for (; left && vleft--; i++, first=0) {
  804.         if (write) {
  805.             while (left) {
  806.                 char c;
  807.                 if(get_user(c, (char *) buffer))
  808.                     return -EFAULT;
  809.                 if (!isspace(c))
  810.                     break;
  811.                 left--;
  812.                 ((char *) buffer)++;
  813.             }
  814.             if (!left)
  815.                 break;
  816.             neg = 0;
  817.             len = left;
  818.             if (len > TMPBUFLEN-1)
  819.                 len = TMPBUFLEN-1;
  820.             if(copy_from_user(buf, buffer, len))
  821.                 return -EFAULT;
  822.             buf[len] = 0;
  823.             p = buf;
  824.             if (*p == '-' && left > 1) {
  825.                 neg = 1;
  826.                 left--, p++;
  827.             }
  828.             if (*p < '0' || *p > '9')
  829.                 break;
  830.             val = simple_strtoul(p, &p, 0);
  831.             len = p-buf;
  832.             if ((len < left) && *p && !isspace(*p))
  833.                 break;
  834.             if (neg)
  835.                 val = -val;
  836.             buffer += len;
  837.             left -= len;
  838.  
  839.             if (min && val < *min++)
  840.                 continue;
  841.             if (max && val > *max++)
  842.                 continue;
  843.             *i = val;
  844.         } else {
  845.             p = buf;
  846.             if (!first)
  847.                 *p++ = '\t';
  848.             sprintf(p, "%d", *i);
  849.             len = strlen(buf);
  850.             if (len > left)
  851.                 len = left;
  852.             if(copy_to_user(buffer, buf, len))
  853.                 return -EFAULT;
  854.             left -= len;
  855.             buffer += len;
  856.         }
  857.     }
  858.  
  859.     if (!write && !first && left) {
  860.         if(put_user('\n', (char *) buffer))
  861.             return -EFAULT;
  862.         left--, buffer++;
  863.     }
  864.     if (write) {
  865.         p = (char *) buffer;
  866.         while (left) {
  867.             char c;
  868.             if(get_user(c, p++))
  869.                 return -EFAULT;
  870.             if (!isspace(c))
  871.                 break;
  872.             left--;
  873.         }
  874.     }
  875.     if (write && first)
  876.         return -EINVAL;
  877.     *lenp -= left;
  878.     filp->f_pos += *lenp;
  879.     return 0;
  880. }
  881.  
  882. /* Like proc_dointvec, but converts seconds to jiffies */
  883. int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
  884.               void *buffer, size_t *lenp)
  885. {
  886.     return do_proc_dointvec(table,write,filp,buffer,lenp,HZ);
  887. }
  888.  
  889. #else /* CONFIG_PROC_FS */
  890.  
  891. int proc_dostring(ctl_table *table, int write, struct file *filp,
  892.           void *buffer, size_t *lenp)
  893. {
  894.     return -ENOSYS;
  895. }
  896.  
  897. static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
  898.                 void *buffer, size_t *lenp)
  899. {
  900.     return -ENOSYS;
  901. }
  902.  
  903. int proc_dointvec(ctl_table *table, int write, struct file *filp,
  904.           void *buffer, size_t *lenp)
  905. {
  906.     return -ENOSYS;
  907. }
  908.  
  909. int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
  910.             void *buffer, size_t *lenp)
  911. {
  912.     return -ENOSYS;
  913. }
  914.  
  915. int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
  916.             void *buffer, size_t *lenp)
  917. {
  918.     return -ENOSYS;
  919. }
  920.  
  921. #endif /* CONFIG_PROC_FS */
  922.  
  923.  
  924. /*
  925.  * General sysctl support routines 
  926.  */
  927.  
  928. /* The generic string strategy routine: */
  929. int sysctl_string(ctl_table *table, int *name, int nlen,
  930.           void *oldval, size_t *oldlenp,
  931.           void *newval, size_t newlen, void **context)
  932. {
  933.     int l, len;
  934.     
  935.     if (!table->data || !table->maxlen) 
  936.         return -ENOTDIR;
  937.     
  938.     if (oldval && oldlenp) {
  939.         if(get_user(len, oldlenp))
  940.             return -EFAULT;
  941.         if (len) {
  942.             l = strlen(table->data);
  943.             if (len > l) len = l;
  944.             if (len >= table->maxlen)
  945.                 len = table->maxlen;
  946.             if(copy_to_user(oldval, table->data, len))
  947.                 return -EFAULT;
  948.             if(put_user(0, ((char *) oldval) + len))
  949.                 return -EFAULT;
  950.             if(put_user(len, oldlenp))
  951.                 return -EFAULT;
  952.         }
  953.     }
  954.     if (newval && newlen) {
  955.         len = newlen;
  956.         if (len > table->maxlen)
  957.             len = table->maxlen;
  958.         if(copy_from_user(table->data, newval, len))
  959.             return -EFAULT;
  960.         if (len == table->maxlen)
  961.             len--;
  962.         ((char *) table->data)[len] = 0;
  963.     }
  964.     return 0;
  965. }
  966.  
  967. /*
  968.  * This function makes sure that all of the integers in the vector
  969.  * are between the minimum and maximum values given in the arrays
  970.  * table->extra1 and table->extra2, respectively.
  971.  */
  972. int sysctl_intvec(ctl_table *table, int *name, int nlen,
  973.         void *oldval, size_t *oldlenp,
  974.         void *newval, size_t newlen, void **context)
  975. {
  976.     int i, length, *vec, *min, *max;
  977.  
  978.     if (newval && newlen) {
  979.         if (newlen % sizeof(int) != 0)
  980.             return -EINVAL;
  981.  
  982.         if (!table->extra1 && !table->extra2)
  983.             return 0;
  984.  
  985.         if (newlen > table->maxlen)
  986.             newlen = table->maxlen;
  987.         length = newlen / sizeof(int);
  988.  
  989.         vec = (int *) newval;
  990.         min = (int *) table->extra1;
  991.         max = (int *) table->extra2;
  992.  
  993.         for (i = 0; i < length; i++) {
  994.             int value;
  995.             get_user(value, vec + i);
  996.             if (min && value < min[i])
  997.                 return -EINVAL;
  998.             if (max && value > max[i])
  999.                 return -EINVAL;
  1000.         }
  1001.     }
  1002.     return 0;
  1003. }
  1004.  
  1005. int do_string (
  1006.     void *oldval, size_t *oldlenp, void *newval, size_t newlen,
  1007.     int rdwr, char *data, size_t max)
  1008. {
  1009.     int l = strlen(data) + 1;
  1010.     if (newval && !rdwr)
  1011.         return -EPERM;
  1012.     if (newval && newlen >= max)
  1013.         return -EINVAL;
  1014.     if (oldval) {
  1015.         int old_l;
  1016.         if(get_user(old_l, oldlenp))
  1017.             return -EFAULT;
  1018.         if (l > old_l)
  1019.             return -ENOMEM;
  1020.         if(put_user(l, oldlenp) || copy_to_user(oldval, data, l))
  1021.             return -EFAULT;
  1022.     }
  1023.     if (newval) {
  1024.         if(copy_from_user(data, newval, newlen))
  1025.             return -EFAULT;
  1026.         data[newlen] = 0;
  1027.     }
  1028.     return 0;
  1029. }
  1030.  
  1031. int do_int (
  1032.     void *oldval, size_t *oldlenp, void *newval, size_t newlen,
  1033.     int rdwr, int *data)
  1034. {
  1035.     if (newval && !rdwr)
  1036.         return -EPERM;
  1037.     if (newval && newlen != sizeof(int))
  1038.         return -EINVAL;
  1039.     if (oldval) {
  1040.         int old_l;
  1041.         if(get_user(old_l, oldlenp))
  1042.             return -EFAULT;
  1043.         if (old_l < sizeof(int))
  1044.             return -ENOMEM;
  1045.         if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int)))
  1046.             return -EFAULT;
  1047.     }
  1048.     if (newval)
  1049.         if(copy_from_user(data, newval, sizeof(int)))
  1050.             return -EFAULT;
  1051.     return 0;
  1052. }
  1053.  
  1054. int do_struct (
  1055.     void *oldval, size_t *oldlenp, void *newval, size_t newlen,
  1056.     int rdwr, void *data, size_t len)
  1057. {
  1058.     if (newval && !rdwr)
  1059.         return -EPERM;
  1060.     if (newval && newlen != len)
  1061.         return -EINVAL;
  1062.     if (oldval) {
  1063.         int old_l;
  1064.         if(get_user(old_l, oldlenp))
  1065.             return -EFAULT;
  1066.         if (old_l < len)
  1067.             return -ENOMEM;
  1068.         if(put_user(len, oldlenp) || copy_to_user(oldval, data, len))
  1069.             return -EFAULT;
  1070.     }
  1071.     if (newval)
  1072.         if(copy_from_user(data, newval, len))
  1073.             return -EFAULT;
  1074.     return 0;
  1075. }
  1076.  
  1077.  
  1078. #else /* CONFIG_SYSCTL */
  1079.  
  1080.  
  1081. extern asmlinkage int sys_sysctl(struct __sysctl_args *args)
  1082. {
  1083.     return -ENOSYS;
  1084. }
  1085.  
  1086. int sysctl_string(ctl_table *table, int *name, int nlen,
  1087.           void *oldval, size_t *oldlenp,
  1088.           void *newval, size_t newlen, void **context)
  1089. {
  1090.     return -ENOSYS;
  1091. }
  1092.  
  1093. int sysctl_intvec(ctl_table *table, int *name, int nlen,
  1094.         void *oldval, size_t *oldlenp,
  1095.         void *newval, size_t newlen, void **context)
  1096. {
  1097.     return -ENOSYS;
  1098. }
  1099.  
  1100. int proc_dostring(ctl_table *table, int write, struct file *filp,
  1101.           void *buffer, size_t *lenp)
  1102. {
  1103.     return -ENOSYS;
  1104. }
  1105.  
  1106. int proc_dointvec(ctl_table *table, int write, struct file *filp,
  1107.           void *buffer, size_t *lenp)
  1108. {
  1109.     return -ENOSYS;
  1110. }
  1111.  
  1112. int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
  1113.             void *buffer, size_t *lenp)
  1114. {
  1115.     return -ENOSYS;
  1116. }
  1117.  
  1118. int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
  1119.             void *buffer, size_t *lenp)
  1120. {
  1121.     return -ENOSYS;
  1122. }
  1123.  
  1124. struct ctl_table_header * register_sysctl_table(ctl_table * table, 
  1125.                         int insert_at_head)
  1126. {
  1127.     return 0;
  1128. }
  1129.  
  1130. void unregister_sysctl_table(struct ctl_table_header * table)
  1131. {
  1132. }
  1133.  
  1134. #endif /* CONFIG_SYSCTL */
  1135.